<?php

// 定义教室可用时间及使用期限
    $classroomAvailability = [
        'A' => [
            'type' => '标准', // 标准教室
            'max_lessons_per_week' => 30, // 每周最多30节课
            'availability' => ['周一' => ['上午', '中午', '下午', '晚上'], '周三' => ['上午', '中午', '下午', '晚上']],
            'disabled_times' => ['周一' => ['下午']], // 周一下午禁排
            'disabled_slots' => ['周一' => ['课节4', '课节5']], // 新增：A 教室周一禁用课节 4 和课节 5
            'time_slots' => [
                '上午' => ['课节1', '课节2'], // 上午分为课节1和课节2
                '中午' => ['课节3'], // 中午为课节3
                '下午' => ['课节4', '课节5'], // 下午分为课节4和课节5
                '晚上' => ['课节6'], // 晚上为课节6
            ],
            'start' => '2025-01-31',
            'end' => '2025-03-01',
        ],
        'B' => [
            'type' => '肢体', // 肢体教室
            'max_lessons_per_week' => 20, // 每周最多20节课
            'availability' => ['周二' => ['上午', '下午'], '周六' => ['上午', '下午'], '周四' => ['上午', '下午']],
            'disabled_times' => ['周一' => ['中午'], '周二' => ['下午']], // 周一中午、周二下午禁排
            'disabled_slots' => ['*' => ['课节4']], // 新增：B 教室禁用课节 2，* 表示所有日期
            'time_slots' => [
                '上午' => ['课节1'], // 上午为课节1
                '下午' => ['课节2'], // 下午为课节2
            ],
            'start' => '2025-02-01',
            'end' => '2025-05-01',
        ],
        'C' => [
            'type' => '书画', // 书画教室
            'max_lessons_per_week' => 25, // 每周最多25节课
            'availability' => ['周六' => ['上午', '下午'], '周一' => ['上午', '下午'], '周日' => ['上午', '下午']],
            'disabled_times' => ['周三' => ['上午']], // 周三上午禁排
            'disabled_slots' => [], // 无额外禁用课节
            'time_slots' => [
                '上午' => ['课节1'], // 上午为课节1
                '下午' => ['课节2'], // 下午为课节2
            ],
            'start' => '2025-01-15',
            'end' => '2025-05-01',
        ],
        'D' => [
            'type' => '综合', // 综合教室
            'max_lessons_per_week' => 26, // 每周最多26节课
            'availability' => ['周五' => ['上午', '下午']],
            'disabled_times' => ['周五' => ['上午', '中午', '下午', '晚上']], // 周五全天禁排
            'disabled_slots' => [], // 无额外禁用课节
            'time_slots' => [
                '上午' => ['课节1'], // 上午为课节1
                '下午' => ['课节2'], // 下午为课节2
            ],
            'start' => '2025-01-20',
            'end' => '2026-02-05',
        ],
        'E' => [
            'type' => '标准', // 标准教室
            'max_lessons_per_week' => 30, // 每周最多30节课
            'availability' => ['周一' => ['上午', '下午'], '周二' => ['上午', '下午'], '周六' => ['上午', '中午', '下午', '晚上']],
            'disabled_times' => ['周四' => ['下午']], // 周四下午禁排
            'disabled_slots' => [], // 无额外禁用课节
            'time_slots' => [
                '上午' => ['课节1'], // 上午为课节1
                '下午' => ['课节2'], // 下午为课节2
            ],
            'start' => '2025-01-31',
            'end' => '2025-03-01',
        ],
    ];

// 定义课程（按优先级排序：舞蹈班和美术班优先）
    $courses = [
        '舞蹈班' => [
            'type' => '舞蹈',
            'count' => 20,
            'classroom_type' => ['肢体', '综合', '书画'],
            'allow_multiple_classes_per_day' => false, // 不允许同一天上两节课
            'fixed_classroom' => true, // 是否每天使用同一间固定教室
            'disabled_times' => ['周一' => ['上午'], '周二' => ['下午']], // 不排周一上午和周二下午
            'allowed_days' => ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
            'required_times' => ['周一' => ['上午'], '周三' => ['下午']], // 必排周一上午和周三下午
            'max_classes_per_week' => 2, // 每周最多上2节课
        ],
        '美术班' => [
            'type' => '美术',
            'count' => 30,
            'classroom_type' => ['书画'],
            'allow_multiple_classes_per_day' => true, // 允许同一天上两节课
            'fixed_classroom' => false, // 不需要每天使用同一间固定教室
            'disabled_times' => ['周三' => ['下午']], // 不排周三下午
            'allowed_days' => ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
            'required_times' => ['周二' => ['下午'], '周四' => ['上午']], // 必排周二下午和周四上午
            'max_classes_per_week' => 2, // 每周最多上2节课
        ],
        '音乐班1' => [
            'type' => '音乐',
            'count' => 30,
            'classroom_type' => ['标准', '综合'],
            'allow_multiple_classes_per_day' => false, // 不允许同一天上两节课
            'fixed_classroom' => true, // 是否每天使用同一间固定教室
            'disabled_times' => [], // 无禁用时间段
            'allowed_days' => ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
            'required_times' => ['周一' => ['下午'], '周二' => ['上午']], // 必排周一下午和周二上午
            'max_classes_per_week' => 2, // 每周最多上2节课
        ],
        '音乐班2' => [
            'type' => '音乐',
            'count' => 30,
            'classroom_type' => ['标准', '综合'],
            'allow_multiple_classes_per_day' => true, // 允许同一天上两节课
            'fixed_classroom' => false, // 不需要每天使用同一间固定教室
            'disabled_times' => ['周六' => ['晚上']], // 不排周六晚上
            'allowed_days' => ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
            'required_times' => ['周六' => ['上午']], // 必排周六上午
            'max_classes_per_week' => 2, // 每周最多上2节课
        ],
        '书法班1' => [
            'type' => '书法',
            'count' => 30,
            'classroom_type' => ['书画', '标准', '综合'],
            'allow_multiple_classes_per_day' => false, // 不允许同一天上两节课
            'fixed_classroom' => true, // 是否每天使用同一间固定教室
            'disabled_times' => ['周日' => ['上午']], // 不排周日上午
            'allowed_days' => ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
            'required_times' => ['周日' => ['下午']], // 必排周日下午
            'max_classes_per_week' => 2, // 每周最多上2节课
        ],
    ];


    // 定义日期范围
    $startDate = '2025-01-31';
    $endDate = '2026-02-05'; // 使用 D 教室的最终期限



$schedules = [];
$publicHolidays = [
    '2025-01-01', // 元旦
    '2025-02-10', // 春节
    '2025-02-11', // 春节
    '2025-02-12', // 春节
    '2025-04-04', // 清明节
    '2025-05-01', // 劳动节
    '2025-06-18', // 端午节
    '2025-09-17', // 中秋节
    '2025-10-01', // 国庆节
    '2025-10-02', // 国庆节
    '2025-10-03', // 国庆节
];



// 初始化排课表、教室占用情况和每周教室使用课节数
$schedule = [];
$classroomOccupancy = []; // 用于记录教室的时间占用情况
$weeklyClassroomUsage = []; // 用于记录每周教室的已使用课节数
$dailyClassUsage = []; // 用于记录每天每个班级的课程数
$classroomAssignment = []; // 用于记录每个班级的固定教室分配
$requiredTimesFailed = []; // 用于记录必排时间失败的情况

// 定义英文星期到中文星期的映射
$weekdayMapping = [
    'Monday' => '周一',
    'Tuesday' => '周二',
    'Wednesday' => '周三',
    'Thursday' => '周四',
    'Friday' => '周五',
    'Saturday' => '周六',
    'Sunday' => '周日'
];

// 定义中文星期到英文星期的映射
$weekdayMappingReverse = array_flip($weekdayMapping);

// 初始化每个教室每天的使用情况
$classroomDailyUsage = [];

// 循环每一天
$period = [];
$currentDate = strtotime($startDate);
while ($currentDate <= strtotime($endDate)) {
    $period[] = date('Y-m-d', $currentDate);
    $currentDate += 86400;
}

foreach ($period as $date) {
    $date=new \DateTime($date);
    $dayOfWeek = $weekdayMapping[$date->format('l')];
    $dateString = $date->format('Y-m-d');
    $weekKey = $date->format('Y-W'); // 用于标识当前周（年份 + 周数）

    // 初始化每周教室使用课节数
    if (!isset($weeklyClassroomUsage[$weekKey])) {
        $weeklyClassroomUsage[$weekKey] = [];
        foreach ($classroomAvailability as $classroom => $info) {
            $weeklyClassroomUsage[$weekKey][$classroom] = 0;
        }
    }

    // 跳过星期天和国定假日
    if (in_array($dateString, $publicHolidays)) {
        continue;
    }

    // 遍历每个教室
    foreach ($classroomAvailability as $classroom => $info) {
        $availability = $info['availability'];
        $classroomType = $info['type']; // 教室类型
        $maxLessonsPerWeek = $info['max_lessons_per_week']; // 每周最大课节数
        $disabledTimes = $info['disabled_times'] ?? []; // 禁用时段
        $disabledSlots = $info['disabled_slots'] ?? []; // 新增：禁用课节
        $timeSlots = $info['time_slots']; // 时段划分
        $classroomStart = new \DateTime($info['start']);
        $classroomEnd = new \DateTime($info['end']);
        $daytimeoindex = $info["daytimeoindex"];

        // 检查当前日期是否在教室的使用期限内
        if ($date >= $classroomStart && $date <= $classroomEnd) {
            if (isset($availability[$dayOfWeek])) {
                foreach ($availability[$dayOfWeek] as $timePeriod) {
                    // 检查当前时段是否是禁用时段  $dayOfWeek周一$timePeriod上午
                    if (isset($disabledTimes[$dayOfWeek]) && in_array($timePeriod, $disabledTimes[$dayOfWeek])) {
                        continue; // 当前时段是禁用时段，跳过
                    }

                    // 遍历当前时段的课节
                    if (array_key_exists($timePeriod,$timeSlots)&&is_array($timeSlots[$timePeriod])) {

                        foreach ($timeSlots[$timePeriod] as $timeSlot) {
                            // 检查当前课节是否是禁用课节 $dayOfWeek周一$timePeriod上午  $timeSlot课节1
                            if (
                                (isset($disabledSlots[$dayOfWeek]) && in_array($timeSlot, $disabledSlots[$dayOfWeek])) ||
                                (isset($disabledSlots['*']) && in_array($timeSlot, $disabledSlots['*']))
                            ) {
                                continue; // 当前课节是禁用课节，跳过
                            }

                            // 标记是否还有课程可排
                            $hasCourseToSchedule = true;
                            while ($hasCourseToSchedule) {
                                // 重置标记
                                $hasCourseToSchedule = false;

                                // 检查教室在该课节是否已被占用
                                $key = $classroom . '-' . $dateString . '-' . $timeSlot;
                                if (isset($classroomOccupancy[$key])) {
                                    break; // 课节已被占用，跳出循环
                                }

                                // 检查本周教室的课节数是否已达到上限
                                if ($weeklyClassroomUsage[$weekKey][$classroom] >= $maxLessonsPerWeek) {
                                    break; // 本周课节数已满，跳出循环
                                }

                                // 遍历每个班级
                                foreach ($courses as $class => &$course) {

                                    if($dateString=="2025-01-31"){
                                        if($classroom=="502教室"){
                                            if($class=="2024级秋季声乐中级班"){
                                                $bug=$course["type"].$timePeriod.$timeSlot;
                                            }
                                        }
                                    }


                                    // 检查教室类型是否匹配
                                    if ($course['count'] > 0 && in_array($classroomType, $course['classroom_type'])) {
                                        // 检查是否允许同一天上两节课
                                        if (!$course['allow_multiple_classes_per_day'] && isset($dailyClassUsage[$dateString][$class]) && $dailyClassUsage[$dateString][$class] >= 1) {
                                            continue; // 不允许同一天上两节课，跳过
                                        }

                                        // 检查是否需要固定教室
                                        if ($course['fixed_classroom'] && !isset($classroomAssignment[$class])) {
                                            $classroomAssignment[$class] = $classroom; // 分配固定教室
                                        } elseif ($course['fixed_classroom'] && $classroomAssignment[$class] != $classroom) {
                                            continue; // 固定教室不匹配，跳过
                                        }

                                        // 检查班级是否禁用了当前时间段
                                        if (isset($course['disabled_times'][$dayOfWeek]) && in_array($timePeriod, $course['disabled_times'][$dayOfWeek])) {
                                            continue; // 班级禁用了当前时间段，跳过
                                        }

                                        // 检查班级是否只在特定天排课
                                        if (!empty($course['allowed_days']) && !in_array($dayOfWeek, $course['allowed_days'])) {
                                            continue; // 班级不在当前天排课，跳过
                                        }


                                        // 检查是否是必排时间段
                                        if (isset($course['required_times'][$dayOfWeek]) && in_array($timePeriod, $course['required_times'][$dayOfWeek])) {
                                            // 必排时间段，优先排课
                                            $schedule[] = [
                                                '班名' => $class,
                                                '教室' => $classroom."({$info['type']})",
                                                '教室类型' => $info["type"],
                                                '课程' => $course["subject_lv"],
                                                '日期' => $dateString,
                                                '周几' => $dayOfWeek, // 添加周几字段
                                                '时段' => $timePeriod,
                                                '课节' => $timeSlot,
                                                '备注' => '必排时间段',
                                                '课节合计' => count($info["daytimeoindex"]),
                                                'end_time'=>$info_oindex_data->end_time,
                                                'classes_id' => $course['classes_id'],
                                                'count_total'=>$course['count_total'],
                                                'class_index' => $course['count_total']-$course['count']+1
                                            ];
                                            $course['count']--;
                                            $classroomOccupancy[$key] = true; // 标记该课节已被占用
                                            $weeklyClassroomUsage[$weekKey][$classroom]++; // 增加本周教室的已使用课节数
                                            $weeklyClassUsage[$weekKey][$class]++; // 增加本周班级的已使用课节数

                                            // 更新每天每个班级的课程数
                                            if (!isset($dailyClassUsage[$dateString][$class])) {
                                                $dailyClassUsage[$dateString][$class] = 0;
                                            }
                                            $dailyClassUsage[$dateString][$class]++;

                                            // 记录教室每天的使用情况
                                            if (!isset($classroomDailyUsage[$classroom][$dateString])) {
                                                $classroomDailyUsage[$classroom][$dateString] = [];
                                            }
                                            $classroomDailyUsage[$classroom][$dateString][$timePeriod . ' ' . $timeSlot] = $class;

                                            $hasCourseToSchedule = true; // 标记还有课程可排
                                            break;
                                        } else {
                                            // 非必排时间段，正常排课
                                            $schedule[] = [
                                                '班名' => $class,
                                                '教室' => $classroom."({$info['type']})",
                                                '日期' => $dateString,
                                                '周几' => $dayOfWeek, // 添加周几字段
                                                '时段' => $timePeriod,
                                                '课程' => $course["subject_lv"],
                                                '课节' => $timeSlot,
                                                '课节合计' => count($info["daytimeoindex"]),
                                                '备注' => '',
                                                'classes_id' => $course['classes_id'],
                                                'start_time'=>$info_oindex_data->start_time,
                                                'end_time'=>$info_oindex_data->end_time,
                                                'count_total'=>$course['count_total'],
                                                'class_index' => $course['count_total']-$course['count']+1
                                            ];
                                            $course['count']--;
                                            $classroomOccupancy[$key] = true; // 标记该课节已被占用
                                            $weeklyClassroomUsage[$weekKey][$classroom]++; // 增加本周教室的已使用课节数

                                            // 更新每天每个班级的课程数
                                            if (!isset($dailyClassUsage[$dateString][$class])) {
                                                $dailyClassUsage[$dateString][$class] = 0;
                                            }
                                            $dailyClassUsage[$dateString][$class]++;

                                            // 记录教室每天的使用情况
                                            if (!isset($classroomDailyUsage[$classroom][$dateString])) {
                                                $classroomDailyUsage[$classroom][$dateString] = [];
                                            }
                                            $classroomDailyUsage[$classroom][$dateString][$timePeriod . ' ' . $timeSlot] = $class;
                                            $hasCourseToSchedule = true; // 标记还有课程可排
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

foreach ($courses as $class => $course) {
    foreach ($course['required_times'] as $day => $times) {
        foreach ($times as $time) {
            $found = false;
            foreach ($schedule as $entry) {
                if ($entry['班名'] == $class && $entry['周几'] == $day && $entry['时段'] == $time) {
                    $found = true;
                    break;
                }
            }
            if (!$found) {
                // 获取必排时间段的具体日期
                $requiredDate = new \DateTime($startDate);
                $dayOfWeek = $weekdayMappingReverse[$day];
                while ($requiredDate->format('l') !== $dayOfWeek) {
                    $requiredDate->modify('next ' . $dayOfWeek);
                }
                if ($requiredDate < $startDate) {
                    $requiredDate->modify('next ' . $dayOfWeek);
                }
                $requiredDateStr = $requiredDate->format('Y-m-d');
                $requiredTimesFailed[] = [
                    '班名' => $class,
                    '日期' => $requiredDateStr,
                    '周几' => $day,
                    '时段' => $time,
                    '备注' => '必排时间段未排上',
                ];
            }
        }
    }
}



// 输出排课表
    echo "班名\t教室\t日期\t周几\t时段\t课节\t备注\n";
    foreach ($schedule as $entry) {
        echo $entry['班名'] . "\t" . $entry['教室'] . "\t" . $entry['日期'] . "\t" . $entry['周几'] . "\t" . $entry['时段'] . "\t" . $entry['课节'] . "\t" . $entry['备注'] . "\n";
    }

// 输出必排时间段未排上的警告
    foreach ($requiredTimesFailed as $entry) {
        echo "警告: " . $entry['班名'] . " 在 " . $entry['日期'] . " " . $entry['周几'] . " " . $entry['时段'] . " 未排上课。" . $entry['备注'] . "\n";
    }

// 检查是否有未排课的班级
    foreach ($courses as $class => $course) {
        if ($course['count'] > 0) {
            echo "警告: {$class} 还有 {$course['count']} 节课未安排。\n";
        }
    }
